﻿using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
using System.Text;
using Test.Dto;
using Test.Entity;
using Test.Interface;

namespace Test.Service
{
    public class UserAppService : IUserAppService
    {
        private readonly IOptionsSnapshot<JWTTokenOption> _jwtTokenOption;
        private readonly UserManager<User> _userManager;
        private readonly RoleManager<Role> _roleManager;
        private readonly ILogger<UserAppService> _logger;

        public UserAppService(IOptionsSnapshot<JWTTokenOption> jwtTokenOption, UserManager<User> userManager, RoleManager<Role> roleManager, ILogger<UserAppService> logger)
        {
            _jwtTokenOption = jwtTokenOption;
            _userManager = userManager;
            _roleManager = roleManager;
            _logger = logger;
        }

        private TokenDto GenerateJwtToken(User user)
        {
            // 1. 定义需要使用到的Claims
            //用于描述即将生成的JWT的主要属性
            var claims = new[]
            {
            new Claim(ClaimTypes.Name, user.UserName),
            //new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),
            };
            var key = Encoding.UTF8.GetBytes(_jwtTokenOption.Value.IssuerSigningKey);
            DateTime expires = DateTime.Now.AddMinutes(_jwtTokenOption.Value.AccessTokenExpiresMinutes);
            var credentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature);
            var jwtSecurityToken = new JwtSecurityToken(
                                            _jwtTokenOption.Value.Issuer,     //Issuer
                                            _jwtTokenOption.Value.Audience,   //Audience
                                            claims: claims,                          //Claims,
                                            DateTime.Now,                    //notBefore
                                            expires: expires,    //expires
                                            signingCredentials: credentials               //Credentials
                                            );
            string token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
            return new TokenDto()
            {
                AccessToken = token,
                TokenType = "Bearer"
            };
        }
        public async Task<TokenDto> RegisterAsync(string username, string password, string email)
        {
            var existingUser = await _userManager.FindByNameAsync(username);
            if (existingUser != null)
            {
                throw new CreateUserFailedException($"注册用户异常: {existingUser.UserName}已经存在！");
            }
            var newUser = new User() { UserName = username, Email = email };
            var isCreated = await _userManager.CreateAsync(newUser, password);
            if (!isCreated.Succeeded)
            {
                throw new CreateUserFailedException($"用户创建失败！{isCreated.Errors}");
            }
            try
            {
                var tokenDto = GenerateJwtToken(newUser);
                return GenerateJwtToken(newUser); // 返回生成的JWT令牌
            }
            catch (Exception ex)
            {
                // 抛出自定义异常，表示生成JWT令牌时发生错误
                throw new GenerateTokenFailedException($"生成JWT的时候发生了一个错误: {ex.Message}", ex);
            }
        }
        public async Task<TokenDto> LoginAsync(string username, string password)
        {
            var existingUser = await _userManager.FindByNameAsync(username) ?? throw new CreateUserFailedException("用户不存在");
            var isCorrect = await _userManager.CheckPasswordAsync(existingUser, password);
            if (!isCorrect)
            {
                // 打印日志
                _logger.LogError(message: $"用户名: {username},密码错误!");
                // 抛出异常
                throw new CreateUserFailedException("密码错误");
            }
            return GenerateJwtToken(existingUser);
        }
    }
    public class CreateUserFailedException : Exception
    {
        public CreateUserFailedException(string message) : base(message)
        {
        }
    }
    public class GenerateTokenFailedException : Exception
    {
        public GenerateTokenFailedException(string message, Exception innerException) : base(message, innerException)
        {
        }
    }
    public class LoginUserFailedException : Exception
    {
        public LoginUserFailedException(string message) : base(message)
        {
        }
    }
}
